package nl.hu.lcv.scheduling;

import java.util.ArrayList;
import java.util.HashMap;

import nl.hu.lcv.agents.Product;
import nl.hu.lcv.blackboard.client.BlackboardClientUtils;
import nl.hu.lcv.blackboard.data.PostItProtos.PostIt;
import nl.hu.lcv.blackboard.data.PostItProtos.PostItBox;
import org.apache.xmlbeans.XmlException;
import xHUAgileManufacturingAFDLSteps.PartDocument.Part;
import xHUAgileManufacturingAFDLSteps.PropertyDocument.Property;
import xHUAgileManufacturingAFDLSteps.StepDocument;

// TODO: Auto-generated Javadoc
/**
 * The Class Utils.
 */
public class Utils {
	
		
	//Get timestep to schedule a step on
	/**
	 * Gets the timestep.
	 *
	 * @param availableSteps the available steps
	 * @param desiredTimeStep the desired time step
	 * @return the timestep
	 */
	public static long getTimestep(ArrayList<Long> availableSteps, long desiredTimeStep)
	{
		int index = -1;
		while(index == -1)
		{			
			desiredTimeStep++;
			index = availableSteps.indexOf(desiredTimeStep);
			if(availableSteps.size() == 0 || desiredTimeStep > availableSteps.get(availableSteps.size()-1))
				return -1;
			
		}
		//System.out.println("Scheduled on " + desiredTimeStep);
		availableSteps.remove(desiredTimeStep);
		return desiredTimeStep;
	}
	
	/**
	 * Gets the availability.
	 *
	 * @param agentName the agent name
	 * @param equiplet the equiplet
	 * @param minTime the min time
	 * @param maxTime the max time
	 * @return the array list
	 */
	public static ArrayList<Long> GetAvailability(String agentName, String equiplet, long minTime, long maxTime)
	{
	
		PostItBox postItBox = PostItBox.newBuilder()
				.setIsWrite(false)
				.setReadOwner(agentName)
				.setZone("BB2")
				.setCurrentTimeStep(minTime)
				.setFilter(PostItBox.Filter.newBuilder().setFiltername("AvailabilityFilter").setDeadline(maxTime).addAgentname(equiplet))
				.build();			 	
			
		postItBox = BlackboardClientUtils.readFromBlackboard(postItBox);
		ArrayList<Long> arr = new ArrayList<Long>();
		for(long i = minTime; i < maxTime; i++)		
			arr.add(i);				
		for(PostIt p : postItBox.getPostItsList())		
			arr.remove(p.getTimestep());		
		System.out.println("Checked  "+ equiplet + ", " + arr.size() + " spots free");
		return arr;	
	}
	
	/**
	 * Gets the current scheduled steps.
	 *
	 * @param agentName the agent name
	 * @param productNames the product names
	 * @return the current scheduled steps
	 */
	public static ArrayList<PostIt> getCurrentScheduledSteps(String agentName,ArrayList<String> productNames)
	{
		PostItBox postItBox = PostItBox.newBuilder()
				.setIsWrite(false)
				.setReadOwner(agentName)
				.setZone("BB2")				
				.setFilter(PostItBox.Filter.newBuilder().setFiltername("InitiateRescheduleFilter").addAllAgentname(productNames))
				.build();			
		postItBox = BlackboardClientUtils.readFromBlackboard(postItBox);	
		return new ArrayList<PostIt>(postItBox.getPostItsList());
	}
	
	/**
	 * First fit.
	 *
	 * @param arr the arr
	 * @param theProduct the the product
	 * @param currentTimeStep the current time step
	 * @param readFromBbBox the read from bb box
	 * @param Mysteps the mysteps
	 * @param availableTimeSteps the available time steps
	 * @return true, if successful
	 */
	public static boolean firstFit(ArrayList<PostIt> arr,  Product theProduct, long currentTimeStep, PostItBox readFromBbBox, HashMap<String, String> Mysteps, HashMap<String,ArrayList<Long>> availableTimeSteps)
	{		
		long TimeStep = currentTimeStep + 1;
		boolean schedulingOk = true;
		int[] timesteps = new int[readFromBbBox.getPostItsCount()];
		for(int i = 1; i <= readFromBbBox.getPostItsCount();i++)
		{
			for(PostIt p : readFromBbBox.getPostItsList())
			{
				if(p.getOrdinal() == i)
				{					
					//System.out.println("Schedule Equiplet:" + Mysteps.get((Integer)p.getPayload()) + ", ProductStep: " + p.getPayload());
					TimeStep = Utils.getTimestep(availableTimeSteps.get(Mysteps.get(Integer.parseInt(p.getPayload()))), TimeStep);
					if(TimeStep != -1)
					{					
						PostIt postIt = null;
						try {
							postIt = PostIt.newBuilder()
									.setOrdinal(i)
									.setOwner(Mysteps.get(StepDocument.Factory.parse(p.getPayload()).getStep().getAction().getVerb()))
									.setTimestep(TimeStep)
									.setPayload(p.getPayload())
									.setProductRef(theProduct.getName())
									.build();
						} catch (XmlException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}		
											
						timesteps[i-1] = (int)TimeStep;										
						arr.add(postIt);
						break;
					}		
					else
					{							
						schedulingOk = false;
						break;
					}
				}					
			}	
			if(!schedulingOk)
				return false;
		}		
		
		theProduct.setTimesteps(timesteps);
		return true;
		
	}	
	
	/**
	 * Reschedule.
	 *
	 * @param arr the arr
	 * @param currentTimeStep the current time step
	 * @param Mysteps the mysteps
	 * @param availableTimeSteps the available time steps
	 * @param productsToReschedule the products to reschedule
	 * @return true, if successful
	 */
	public static boolean reschedule(ArrayList<PostIt> arr,long currentTimeStep,HashMap<String, String> Mysteps, HashMap<String,ArrayList<Long>> availableTimeSteps, ArrayList<Product> productsToReschedule)
	{
		boolean schedulingOk = true;
		
		for(Product p : productsToReschedule)
		{
			long TimeStep = currentTimeStep + 1;
			int[] timesteps = p.getTimesteps();
			int firstStepToReschedule = 0;
			for(int i : p.getTimesteps())
			{
				if(i > currentTimeStep)
				{
					firstStepToReschedule = i;
					break;									
				}								
			}
			for(int i = firstStepToReschedule; i < p.getSteps().length;i++)
			{
				//System.out.println("ReSchedule Equiplet:" + Mysteps.get(i) + ", ProductStep: " + i);
				
				TimeStep = Utils.getTimestep(availableTimeSteps.get(Mysteps.get(p.getSteps()[i])), TimeStep);
				if(TimeStep != -1)
				{					
					PostIt postIt = null;
					try {
						postIt = PostIt.newBuilder()
								.setOrdinal(i+1)
								.setOwner(Mysteps.get(StepDocument.Factory.parse(p.getSteps()[i]).getStep().getAction().getVerb()))
								.setTimestep(TimeStep)
								.setPayload(""+(p.getSteps()[i]))
								.setProductRef(p.getName())
								.build();
					} catch (XmlException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}		
					timesteps[i] = (int)TimeStep;												
					arr.add(postIt);									
				}		
				else
				{							
					schedulingOk = false;
					break;
				}		

			}			
				
				
			
			if(!schedulingOk)
			{
				return false;
			}
			
			p.setTimesteps(timesteps);
		}
		return true;
	}
	
	
}
